package com.google.code.ojar.sendtemplatemail.console.exec;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingOptionException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.cli.UnrecognizedOptionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.ojar.sendtemplatemail.app.SendMail;
import com.google.code.ojar.sendtemplatemail.app.dto.Attachment;
import com.google.code.ojar.sendtemplatemail.app.dto.Mail;
import com.google.code.ojar.sendtemplatemail.app.dto.NotSendMail;
import com.google.code.ojar.sendtemplatemail.app.exception.AppException;
import com.google.code.ojar.sendtemplatemail.app.exception.EmailTemplateNotFound;
import com.google.code.ojar.sendtemplatemail.app.exception.MissingAddressException;
import com.google.code.ojar.sendtemplatemail.app.exception.MissingConfigurationException;
import com.google.code.ojar.sendtemplatemail.app.exception.SendMailException;
import com.google.code.ojar.sendtemplatemail.app.msggenerators.MsgGenerator;
import com.google.code.ojar.sendtemplatemail.app.resendhandler.ResendFactory;
import com.google.code.ojar.sendtemplatemail.app.resendhandler.ResendHandler;
import com.google.code.ojar.sendtemplatemail.app.utils.SendMailUtils;

@SuppressWarnings("static-access")
/**
 * Class that receive the commands via console calling and invokes the sendMail core
 * @author ottoabreu
 *
 */
public final class SendMailMain {
	// logger
	private static final Logger logger = LoggerFactory
			.getLogger(SendMailMain.class);
	private static Options options;
	private static HelpFormatter formatter = new HelpFormatter();
	// options definitions
	private static final String COMMAND_GENERATOR_NAME = "g";
	private static final String COMMAND_TEMPLATE_ID_NAME = "tid";
	private static final String COMMAND_TEMPLATE_REPLACEMENTS = "r";
	private static final String COMMAND_TOADDS = "to";
	private static final String COMMAND_CCADDS = "cc";
	private static final String COMMAND_BCADDS = "bc";
	private static final String COMMAND_ATTCH = "att";

	private static final int EXIT_CODE_SUCESS = 0;
	private static final int EXIT_CODE_MISSING_REQUIRED_PARAM = -1;
	private static final int EXIT_CODE_WRONG_CONSOLE_COMAND = -2;
	private static final int EXIT_CODE_UNPARSEABLE_PARAM = -3;
	private static final int EXIT_CODE_WRONG_CONF = -4;
	private static final int EXIT_CODE_WRONG_TEMPLATE_NAN = -5;
	private static final int EXIT_CODE_MISSING_TEMPLATE = -6;
	private static final int EXIT_CODE_SET_PROPERTY_ERROR = -7;
	private static final int EXIT_CODE_MISSING_ADDR = -8;
	private static final int EXIT_CODE_APP_ERROR = -9;
	private static final int EXIT_CODE_GENERIC_ERROR = -10;

	// se crean las opciones de consola
	static {
		options = new Options();
		Option generator = OptionBuilder.withArgName("name").hasArgs(1)
				.withDescription("set the name of the generator to be use")
				.isRequired().create(COMMAND_GENERATOR_NAME);

		Option templateId = OptionBuilder
				.withArgName("templateId")
				.hasArgs(1)
				.withDescription(
						"set the template to use is optional if the generator use one template")
				.create(COMMAND_TEMPLATE_ID_NAME);

		Option remplaceForce = OptionBuilder
				.withArgName("remplacement")
				.hasArgs()
				.withValueSeparator(',')
				.withDescription(
						"force a replace, a set of words separated by a coma (,), if sentenses are used, EACH WORD HAS TO BE SEPARATED BY UNDER SCORE(_),DO NO LEAVE WHITES SPACES. the generator will remplace the words or sentences in the same order EXAMPLE: hello,this_is_a_sentence,this_is_a_very_long_example_sentence_")
				.create(COMMAND_TEMPLATE_REPLACEMENTS);
		Option toAddr = OptionBuilder
				.withArgName("to addresses")
				.hasArgs()
				.withValueSeparator(',')
				.isRequired()
				.withDescription(
						"a set( can be only one) of email addresses separated by a coma (,) (main destination addresses)")
				.create(COMMAND_TOADDS);
		Option toccddr = OptionBuilder
				.withArgName("copy addresses")
				.hasArgs()
				.withValueSeparator(',')
				.withDescription(
						" OPTIONAL a set( can be only one) of email addresses separated by a coma (,) (copy destination addresses)")
				.create(COMMAND_CCADDS);
		Option tobcddr = OptionBuilder
				.withArgName("blind copy addresses")
				.hasArgs()
				.withValueSeparator(',')
				.withDescription(
						" OPTIONAL a set( can be only one) of email addresses separated by a coma (,) ( hidden copy destination addresses)")
				.create(COMMAND_BCADDS);

		Option attchs = OptionBuilder
				.withArgName("attached files")
				.hasArgs()
				.withValueSeparator(',')
				.withDescription(
						" OPTIONAL a set( can be only one) path to files that will be puted as attach, separated by a coma (,) ")
				.create(COMMAND_ATTCH);

		options.addOption(generator);
		options.addOption(templateId);
		options.addOption(remplaceForce);
		options.addOption(toAddr);
		options.addOption(toccddr);
		options.addOption(tobcddr);
		options.addOption(attchs);

	}

	/**
	 * Main Method
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		CommandLineParser parser = new PosixParser();
		String generator = null;
		Integer templateIdNumber = null;
		String[] replacement = null;
		List<String> toAdds = null;
		List<String> ccAddrs = null;
		List<String> bccAdd = null;
		List<Attachment> attchList = null;
		Mail msg = null;

		try {

			CommandLine cmd = parser.parse(options, args);
			generator = cmd.getOptionValue(COMMAND_GENERATOR_NAME);
			toAdds = Arrays.asList(cmd.getOptionValues(COMMAND_TOADDS));
			logger.info("invoked SendMail with: generator: " + generator
					+ " and toAdd" + toAdds);
			if (cmd.hasOption(COMMAND_TEMPLATE_ID_NAME)) {
				String templateId = cmd
						.getOptionValue(COMMAND_TEMPLATE_ID_NAME);
				logger.info("invoked sendmail with template id: " + templateId);
				templateIdNumber = new Integer(templateId);
			}

			if (cmd.hasOption(COMMAND_CCADDS)) {
				ccAddrs = Arrays.asList(cmd.getOptionValues(COMMAND_CCADDS));
				logger.info("invoked SendMail with ccAddrs: " + ccAddrs);
			}
			if (cmd.hasOption(COMMAND_BCADDS)) {
				bccAdd = Arrays.asList(cmd.getOptionValues(COMMAND_BCADDS));
				logger.info("invoked SendMail with ccAddrs: " + bccAdd);
			}

			if (cmd.hasOption(COMMAND_TEMPLATE_REPLACEMENTS)) {
				replacement = new String[cmd
						.getOptionValues(COMMAND_TEMPLATE_REPLACEMENTS).length];

				String[] originalArray = cmd
						.getOptionValues(COMMAND_TEMPLATE_REPLACEMENTS);
				logger.info("invoked SendMail with replacement: "
						+ Arrays.toString(originalArray));
				for (int i = 0; i < originalArray.length; i++) {
					replacement[i] = replaceUnderScoreByWhiteSpaces(originalArray[i]);
					logger.debug("replacement:" + replacement[i]);
				}

			}
			if (cmd.hasOption(COMMAND_ATTCH)) {
				List<String> attch = Arrays.asList(cmd
						.getOptionValues(COMMAND_BCADDS));
				logger.debug("nvoked SendMail with attachs:" + attch);
				attchList = getAttachemtsList(attch);

			}

			MsgGenerator generatorInstance = SendMailUtils.generatorFactory(
					generator, SendMailMain.class.getClassLoader());
			logger.info("Msg Generator instance created");
			msg = generatorInstance.generateMailMsg(toAdds, ccAddrs, bccAdd,
					replacement, templateIdNumber);
			msg.setAttachments(attchList);
			logger.info("Email Msg Created");
			SendMail.send(msg);
			logger.info("Email Sent");

		} catch (UnrecognizedOptionException e) {
			formatter.printHelp("SendMail, remember to use only lower cases",
					options);
			logger.error("UnrecognizedOptionException,exit code: "
					+ EXIT_CODE_WRONG_CONSOLE_COMAND, e);
			System.exit(EXIT_CODE_WRONG_CONSOLE_COMAND);
		} catch (MissingOptionException e) {
			formatter.printHelp("SendMail, remember to use only lower cases",
					options);
			logger.error("MissingOptionException,exit code: "
					+ EXIT_CODE_MISSING_REQUIRED_PARAM, e);
			System.exit(EXIT_CODE_MISSING_REQUIRED_PARAM);
		} catch (ParseException e) {
			formatter.printHelp("SendMail, remember to use only lower cases",
					options);
			logger.error("ParseException,exit code: "
					+ EXIT_CODE_UNPARSEABLE_PARAM, e);
			System.exit(EXIT_CODE_UNPARSEABLE_PARAM);
		} catch (MissingConfigurationException e) {
			logger.error("MissingConfigurationException,exit code: "
					+ EXIT_CODE_WRONG_CONF, e);
			// escribo xml para ver si arreglan la conf
			SendMailMain.generateNotSended(generator, msg, e);

			System.exit(EXIT_CODE_WRONG_CONF);
		} catch (NumberFormatException e) {
			logger.error("template number is wrong,exit code: "
					+ EXIT_CODE_WRONG_TEMPLATE_NAN);
			System.exit(EXIT_CODE_WRONG_TEMPLATE_NAN);
		} catch (AppException e) {
			logger.error("AppException,exit code: " + EXIT_CODE_APP_ERROR, e);
			System.exit(EXIT_CODE_APP_ERROR);
		} catch (EmailTemplateNotFound e) {
			logger.error("missing template: exit code "
					+ EXIT_CODE_MISSING_TEMPLATE, e);

			// escribo el xml para ver si le colocan el template y se envia
			SendMailMain.generateNotSended(generator, msg, e);

			System.exit(EXIT_CODE_MISSING_TEMPLATE);
		} catch (MissingAddressException e) {
			logger.error(
					"missing address: exit code " + EXIT_CODE_MISSING_ADDR, e);
			System.exit(EXIT_CODE_MISSING_ADDR);
		} catch (SendMailException e) {
			// creo xml si hay error de conexion
			if (e.isConnectionError()) {

				SendMailMain.generateNotSended(generator, msg, e);

			} else {
				logger.error("Can't set email properties, exit code: "
						+ EXIT_CODE_SET_PROPERTY_ERROR, e);
				System.exit(EXIT_CODE_SET_PROPERTY_ERROR);
			}
		} catch (Throwable e) {
			logger.error("A wild exception has appears!! exit code: "
					+ EXIT_CODE_GENERIC_ERROR, e);
			System.exit(EXIT_CODE_GENERIC_ERROR);
		}
		logger.info("exit success");
		System.exit(EXIT_CODE_SUCESS);

	}

	/**
	 * Replace the under scores by white spaces
	 * 
	 * @param original
	 *            {@link String}
	 * @return {@link String}
	 */
	private static String replaceUnderScoreByWhiteSpaces(String original) {
		String replaced = null;
		Pattern patt = Pattern.compile("_");
		Matcher matcher = patt.matcher(original);
		if (matcher.find()) {
			replaced = matcher.replaceAll(" ");
		} else {
			replaced = original;
		}
		return replaced;
	}

	/**
	 * Method that generate the not sended mail
	 * 
	 * @param generator
	 *            {@link String}
	 * @param msg
	 *            {@link Mail}
	 * @param e
	 *            {@link Exception}
	 */
	private static void generateNotSended(String generator, Mail msg,
			Exception e) {
		ResendFactory factory = ResendFactory.getInstance();
		try {
			ResendHandler handler = factory.gethandler();
			NotSendMail notSend = new NotSendMail(generator, msg);

			handler.generate(notSend);
		} catch (Exception e1) {
			logger.error("can't create not sended file  due an error ", e);
		}
	}

	/**
	 * Generates a list whit object atachments from a list of string
	 * 
	 * @param atchStringLists
	 *            {@link List}<String> whit the string of the paths
	 * @return {@link List}<Attachment>
	 */
	private static List<Attachment> getAttachemtsList(
			final List<String> atchStringLists) {
		List<Attachment> attch = new ArrayList<Attachment>(
				atchStringLists.size());
		for (String attachmentString : atchStringLists) {
			Pattern patt = Pattern.compile("([A-Za-z0-9.])+(\\.\\w{2,4})+$");
			Matcher match = patt.matcher(attachmentString);
			match.find();
			Attachment attachment = new Attachment(attachmentString, null,
					match.group());
			attch.add(attachment);
		}

		return attch;
	}

	/**
	 * Private constructor
	 */
	private SendMailMain() {

	}

}
